﻿// Copyright (C) 2013-2014 Ralph Becket
// Released under a variant of the Microsoft Public License -- see ../LICENCE.txt.
//
// This file extends Rawb with functions to asynchronously load JavaScript and HTML.

var rawb = rawb || {};

(function () {

    /*

!! rawb.nonOverlappingAsync(async, throttle)

Construct an asynchronous function taking pass/fail callbacks
such that only the last in any sequence of overlapping
calls is processed.

To be more precise, if _g = rawb.nonOverlappingAsync(f, n)_ then
calling _g(x, pass, fail)_ will have the following behaviour:
* nothing will happen for at least _n_ milliseconds; then
* nothing will happen if any calls to _g_ have been made in the intervening period;
* otherwise _f(x, passX, failX)_ will be invoked where _passX_ and _failX_ are the
same as _pass_ and _fail_ respectively except that nothing will happen if any
calls to _g_ have been made in the period between _f_ being invoked and _passX_
or _failX_ being invoked by _f_.
    
*Parameters*

*async:* _function(arg, pass, fail)_

An asynchronous function (typically an AJAX request) taking an
argument _arg_ and _pass_ and _fail_ callbacks.  If the call
succeeds, _async_ should call _pass_ with the response; if the
call fails, _async_ should call _fail_ with the reason.

*throttle:* _number_
Optional (default 0).

The number of milliseconds to defer calling _async_.  If this
argument is omitted or is not a positive number, then _async_
is called immediately.

    */

    rawb.nonOverlappingAsync = function (async, throttle) {
        // The counter used to check for overlapping calls.
        var n = 0;
        return function (x, pass, fail) {
            // The asynchronous call with overlap checking.
            var asyncN = (function (n0) {
                return function () {
                    if (n0 !== n) return;
                    var chkN = function (f) {
                        return function (a) {
                            if (n0 === n) f(a);
                        };
                    };
                    async(x, chkN(pass), chkN(fail));
                };
            })(++n);
            // Only defer the asynchronous call if we have a throttle set.
            if (0 < throttle) setTimeout(asyncN, throttle); else asyncN();
        };
    };
})();